package com.demo.forkjoin;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Created by xiangty on 2021/7/26
 */
public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test1();

//        thenComposeDemo();

//        thenCombineDemo();

//        theApplyDemo();

//        thenApplyAsyncDemo();

    }

    private static void thenApplyAsyncDemo() {
        System.out.println(Thread.currentThread().getName() + "   begin");

        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   1");
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "1";
        }).thenApplyAsync(one -> {
            System.out.println(Thread.currentThread().getName() + "   2");
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "返回值one： " + one + " 2";
        });

        System.out.println(Thread.currentThread().getName() + "   do things ...");
        System.out.println(Thread.currentThread().getName() + "   子线程做完了: " + completableFuture.join());

        /*
            main   begin
            ForkJoinPool.commonPool-worker-1   1
            main   do things ...
            ForkJoinPool.commonPool-worker-1   2
            main   子线程做完了: 返回值one： 1 2
         */
    }

    private static void theApplyDemo() {
        System.out.println(Thread.currentThread().getName() + "   begin");

        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   1");
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "1";
        }).thenApply(one -> {
            System.out.println(Thread.currentThread().getName() + "   2");
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "返回值one： " + one + " 2";
        });

        System.out.println(Thread.currentThread().getName() + "   do things ...");
        System.out.println(Thread.currentThread().getName() + "   子线程做完了: " + completableFuture.join());

        /*
            main   begin
            ForkJoinPool.commonPool-worker-1   1
            main   do things ...
            ForkJoinPool.commonPool-worker-1   2
            main   子线程做完了: 返回值one： 1 2
         */
    }

    /**
     * then Combine 然后 结合
     */
    private static void thenCombineDemo() {
        System.out.println(Thread.currentThread().getName() + "   小白进入餐厅");
        System.out.println(Thread.currentThread().getName() + "   小白点了一份番茄炒蛋+一份米饭");

        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   厨师炒番茄炒蛋");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "番茄炒蛋";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   服务员蒸饭");
            return "一份米饭";
        }), (dish, rice) -> {
            System.out.println(Thread.currentThread().getName() + "   服务员打了一份米饭");
            return dish + " + " + rice;
        });

        System.out.println(Thread.currentThread().getName() + "   小白在打游戏");
        System.out.println(Thread.currentThread().getName() + "   小白开吃" + completableFuture.join());

        /*
            输出结果：
            main   小白点了一份番茄炒蛋+一份米饭
            ForkJoinPool.commonPool-worker-1   厨师炒番茄炒蛋
            ForkJoinPool.commonPool-worker-2   服务员蒸饭
            main   小白在打游戏
            ForkJoinPool.commonPool-worker-1   服务员打了一份米饭
            main   小白开吃番茄炒蛋 + 一份米饭
         */
    }

    /**
     * then Compose 然后 组成
     * <p>
     * 两个线程是串行的
     */
    private static void thenComposeDemo() {
        System.out.println(Thread.currentThread().getName() + "   小白进入餐厅");
        System.out.println(Thread.currentThread().getName() + "   小白点了一份番茄炒蛋+一份米饭");

        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   厨师炒番茄炒蛋");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "番茄炒蛋";
        }).thenCompose(dish -> CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "   服务员打了一份米饭");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return dish + " + 一份米饭";
        }));

        System.out.println(Thread.currentThread().getName() + "   小白在打游戏");
        System.out.println(Thread.currentThread().getName() + "   小白开吃" + completableFuture.join());

        /*
            输出结果：
            main   小白进入餐厅
            main   小白点了一份番茄炒蛋+一份米饭
            ForkJoinPool.commonPool-worker-1   厨师炒番茄炒蛋
            main   小白在打游戏
            ForkJoinPool.commonPool-worker-1   服务员打了一份米饭
            main   小白开吃番茄炒蛋 + 一份米饭
         */
    }

    private static void test1() throws InterruptedException, ExecutionException {
        // 没有返回值异步调用
//        CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(() -> {
//            System.out.println(Thread.currentThread().getName() + " completableFuture1");
//        });
//        completableFuture1.get();

        // 有返回值异步调用
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " completableFuture2");
            // 模拟异常
            int i = 10 / 0;
            return 1024;
        });
        completableFuture2.whenComplete((t, u) -> {
            System.out.println("----- whenComplete 返回值t：" + t);
            System.out.println("----- whenComplete 异常信息u：" + u);
        }).exceptionally(e -> {
            System.out.println("exceptionally中的 处理的异常信息：" + e.getMessage());
            return 111;
        }).get();

        /*
            ForkJoinPool.commonPool-worker-1 completableFuture2
            ----- whenComplete 返回值t：null
            ----- whenComplete 异常信息u：java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
            exceptionally中的 处理的异常信息：java.lang.ArithmeticException: / by zero
         */
    }


}
